#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <net/if.h>
#include <netdb.h>

int open_master_pty(char *cname, int clen)
{
	int fd = posix_openpt(O_RDWR | O_NOCTTY);
	if (fd < 0) {
		perror("posix_openpt");
		return -1;
	}
	if (grantpt(fd) < 0) {
		perror("grantpt");
		return -1;
	}
	if (ptsname_r(fd, cname, clen) < 0) {
		perror("ptsname_r");
		return -1;
	}
	if (unlockpt(fd) < 0) {
		perror("unlockpt");
		return -1;
	}
	return fd;
}

int pty_fork(int *mdev, char *cname, int clen, struct termios *tms)
{
	int fd = open_master_pty(cname, clen);
	if (fd < 0) {
		perror("open_master_pty");
		return -1;
	}

	pid_t pid = fork();
	if (pid < 0) {
		perror("fork");
		return -1;
	}
	if (pid) {
		*mdev = fd;
		return pid;
	}

	if (setsid() < 0) {
		perror("setsid");
		return -1;
	}
	close(fd);

	int sfd = open(cname, O_RDWR);
	if (tms) {
		if (tcsetattr(sfd, TCSANOW, tms) < 0) {
			perror("tcsetattr");
			return -1;
		}
	}

	dup2(sfd, STDIN_FILENO);
	dup2(sfd, STDOUT_FILENO);
	dup2(sfd, STDERR_FILENO);

	return 0;
}

int main()
{
	int path_max = 256;
	char cname[path_max];
	int mfd = 0;

	if (pty_fork(&mfd, cname, sizeof(cname), NULL) == 0) {
		execlp("bash", "bash", NULL);
		exit(0);
	}

	int pfd = open("/tmp/javscript", O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IWGRP);
	if (pfd < 0) {
		perror("open javscript");
		return -1;
	}

	struct termios tms, org_tms;
	tcgetattr(STDIN_FILENO, &tms);
	org_tms = tms;
	cfmakeraw(&tms);
	tcsetattr(STDIN_FILENO, TCSANOW, &tms);

	fd_set rset, orset;
	FD_ZERO(&orset);
	FD_SET(mfd, &orset);
	FD_SET(STDIN_FILENO, &orset);
	int maxfd = mfd > STDIN_FILENO ? mfd : STDIN_FILENO;
	char buf[2048];
	printf("Hello world\n");
	for (;;) {
		rset = orset;
		if (select(maxfd + 1, &rset, NULL, NULL, NULL) < 0) {
			continue;
		}

		if (FD_ISSET(mfd, &rset)) {
			int len = read(mfd, buf, sizeof(buf));
			if (len < 0) {
				continue;
			}
			write(STDOUT_FILENO, buf, len);
		}

		if (FD_ISSET(STDIN_FILENO, &rset)) {
			int len = read(STDIN_FILENO, buf, len);
			if (len < 0) {
				continue;
			}
			write(mfd, buf, len);
			write(STDOUT_FILENO, buf, len);
		}
	}

	return 0;
}